﻿using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Linq.Expressions;
using Inovout.Data.Domain;
using Inovout.Data.Repository;
using Inovout.Descriptor;
using Inovout.Web.Mvc;
using System.Web.Mvc.Html;

namespace System.Web.Mvc
{
    public static class ViewDataDictionaryExtensions
    {
        internal static readonly string AdditionalViewDataKeyPrefix = "_additional";
        internal static readonly string DataSourcePrefix = AdditionalViewDataKeyPrefix + "_WidgetModelDataSource_";
        internal static string GetDataSourceKey(string property)
        {
            return DataSourcePrefix + property;
        }
        public static void CopyAdditionalViewData(this ViewDataDictionary viewData, IDictionary<string, object> additionalViewData)
        {
            if (additionalViewData != null)
            {
                foreach (var kv in additionalViewData)
                {
                    viewData[kv.Key] = kv.Value;
                }
            }
        }
        public static void AddDataSource<TModel, TProperty, TSource>(this ViewDataDictionary<TModel> viewData, Expression<Func<TModel, TProperty>> source, Func<TSource> func)
        {
            AddDataSource(viewData, ExpressionHelper.GetExpressionText(source), func);
        }
        public static void AddDataSource<TSource>(this ViewDataDictionary viewData, string source, Func<TSource> func)
        {
            viewData[GetDataSourceKey(source)] = func;
        }
        internal static TSource GetSource<TSource>(object source)
        {
            if (source is Delegate)
            {
                return ((Func<TSource>)source)();
            }
            return (TSource)source;
        }
        internal static IEnumerable GetSource(object source)
        {
            return GetSource<IEnumerable>(source);
        }
        public static void SetFilterCriterias(this ViewDataDictionary viewData, IEnumerable<FilterCriteria> filterCriterias, IEnumerable collection)
        {
            viewData[QueryCriteriaHelper.DefaultFilterCriterionsKey + collection.GetHashCode().ToString()] = filterCriterias;
        }
        public static void SetOrderCriterias(this ViewDataDictionary viewData, OrderCriteria[] orderCriterias, IEnumerable collection)
        {
            viewData[QueryCriteriaHelper.DefaultOrderCriterionsKey + collection.GetHashCode().ToString()] = orderCriterias;
        }
        public static void SetQueryCriteria(this ViewDataDictionary viewData, QueryCriteria queryCriteria, IEnumerable collection)
        {
            SetFilterCriterias(viewData, queryCriteria.Filters, collection);
            SetOrderCriterias(viewData, queryCriteria.Orders.ToArray(),collection);      
  }
        public static QueryCriteria GetQueryCriteria(this ViewDataDictionary viewData, IEnumerable collection)
        {
            return new QueryCriteria(GetFilterCriterias(viewData, collection), GetOrderCriterias(viewData, collection));
        }
        public static IEnumerable<FilterCriteria> GetFilterCriterias(this ViewDataDictionary viewData, IEnumerable collection)
        {
            return (IEnumerable<FilterCriteria>)viewData[QueryCriteriaHelper.DefaultFilterCriterionsKey + collection.GetHashCode().ToString()];
        }
        public static OrderCriteria[] GetOrderCriterias(this ViewDataDictionary viewData, IEnumerable collection)
        {
            return (OrderCriteria[])viewData[QueryCriteriaHelper.DefaultOrderCriterionsKey + collection.GetHashCode().ToString()];
        }
        private static readonly string TreeOfDataSourcSsuffix = "Tree";
        public static Tree GetDataSourceOfTree(this ViewDataDictionary viewData)
        {
            return GetDataSourceOfTree(viewData, viewData.ModelMetadata.AsWidgetModelMetadata());
        }
        internal static Tree GetDataSourceOfTree(this ViewDataDictionary viewData, WidgetModelMetadata metadata)
        {
            Tree tree = null;
            string treeOfDataSourcKey = GetDataSourceKey(metadata.PropertyName) + TreeOfDataSourcSsuffix;
            if (viewData.TryGetValue(treeOfDataSourcKey, out tree))
            {
                return tree;
            }
            PropertyDescriptor valuePropertyDescriptor = TypeDescriptor.Get(metadata.ModelType).GetProperty(metadata.SelectTextValueHtml[0]);
            PropertyDescriptor textPropertyDescriptor = TypeDescriptor.Get(metadata.ModelType).GetProperty(metadata.SelectTextValueHtml[1]);

            IEnumerable<object> defaultValues = null;
            if (metadata.Model is IEnumerable<string>)
            {
                defaultValues = (IEnumerable<string>)metadata.Model;
            }
            else if (metadata.Model is IEnumerable<object>)
            {
                defaultValues = (IEnumerable<object>)metadata.Model;
                defaultValues = defaultValues.Select(v => valuePropertyDescriptor.GetValue(v));
            }
            else if (metadata.Model == null)
            {
                defaultValues = Enumerable.Empty<object>();
            }
            else
            {
                defaultValues = new object[] { valuePropertyDescriptor.GetValue(metadata.Model) };
            }
            IEnumerable<string> selectedValues = from object value in defaultValues
                                                 select Convert.ToString(value, CultureInfo.CurrentCulture);
            selectedValues = selectedValues ?? Enumerable.Empty<string>();
            ITreeDataObject source = GetSource<ITreeDataObject>(viewData[GetDataSourceKey(metadata.PropertyName)]) as ITreeDataObject;
            tree = new Tree(metadata.ModelType, source, valuePropertyDescriptor.Name, textPropertyDescriptor.Name, selectedValues.ToArray());
            viewData[treeOfDataSourcKey] = tree;
            return tree;
        }
        private static readonly string SelectListOfDataSourcSsuffix = "SelectList";
        private static readonly string EnumOfDataSourcSsuffix = "Enum";
        public static IEnumerable<SelectListItem> GetDataSourceOfSelectList(this ViewDataDictionary viewData, Enum value)
        {
            IEnumerable<SelectListItem> selectList = null;
            Type type = value == null ? viewData.ModelMetadata.ModelType : value.GetType();
            string selectListOfDataSourcKey = GetDataSourceKey(type.FullName) + EnumOfDataSourcSsuffix;
            if (viewData.TryGetValue(selectListOfDataSourcKey, out selectList))
            {
                return selectList;
            }
            string valueString = ((object)value) == null ? null : value.ToString();
            selectList = EnumDescriptor.Get(type).EnumItems.Select(e =>
            new SelectListItem { Text = e.Alias, Value = e.Value.ToString(), Selected = e.Value.ToString() == valueString });

            viewData[selectListOfDataSourcKey] = selectList;
            return selectList;
        }
        public static IEnumerable<SelectListItem> GetDataSourceOfSelectList(this ViewDataDictionary viewData)
        {
            return GetDataSourceOfSelectList(viewData, viewData.ModelMetadata.AsWidgetModelMetadata());
        }
        internal static IEnumerable<SelectListItem> GetDataSourceOfSelectList(this ViewDataDictionary viewData, WidgetModelMetadata metadata)
        {
            List<SelectListItem> selectList = null;
            string selectListOfDataSourcKey = GetDataSourceKey(metadata.PropertyName) + SelectListOfDataSourcSsuffix;
            if (viewData.TryGetValue(selectListOfDataSourcKey, out selectList))
            {
                return selectList;
            }
            PropertyDescriptor valuePropertyDescriptor = TypeDescriptor.Get(metadata.ModelType).GetProperty(metadata.SelectTextValueHtml[0]);
            PropertyDescriptor textPropertyDescriptor = TypeDescriptor.Get(metadata.ModelType).GetProperty(metadata.SelectTextValueHtml[1]);

            IEnumerable<object> defaultValues = null;
            if (metadata.Model is IEnumerable<string>)
            {
                defaultValues = (IEnumerable<string>)metadata.Model;
            }
            else if (metadata.Model is IEnumerable<object>)
            {
                defaultValues = (IEnumerable<object>)metadata.Model;
                defaultValues = defaultValues.Select(v => valuePropertyDescriptor.GetValue(v));
            }
            else if (metadata.Model == null)
            {
                defaultValues = Enumerable.Empty<object>();
            }
            else
            {
                defaultValues = new object[] { metadata.Model };
            }
            IEnumerable<string> selectedValues = from object value in defaultValues
                                                 select Convert.ToString(value, CultureInfo.CurrentCulture);
            IEnumerable source = GetSource(viewData[GetDataSourceKey(metadata.PropertyName)]);
            selectList = new List<SelectListItem>();
            foreach (var item in source)
            {
                string text = Convert.ToString(textPropertyDescriptor.GetValue(item));
                string value = Convert.ToString(valuePropertyDescriptor.GetValue(item));
                selectList.Add(new SelectListItem { Text = text, Value = value, Selected = (!string.IsNullOrEmpty(value)) ? selectedValues.Contains(value) : selectedValues.Contains(text) });
            }

            //var selectList = new SelectList(),
            //    metadata.SelectTextValueHtml[0],
            //    metadata.SelectTextValueHtml[1],
            //   defaultValues);
            viewData[selectListOfDataSourcKey] = selectList;
            return selectList;
        }
    }

}
